package com.wn.framework.adapter

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewParent
import android.widget.LinearLayout
import androidx.annotation.IntRange
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding

/**
 * @Author: wn
 * @Date: 2024/10/31 15:52
 * @Description: RecyclerView 的 公用 adapter
 * 1 可以 添加 header footer 布局
 * 2 不调用 addHeadView , addFootView 默认 没有 额外的 头尾 布局
 * 3 子类 只需要 实现 提供 xml ,渲染xml 即可
 * 4 多种 数据操作方案 可以参考
 */
abstract class BaseRecyclerViewAdapter<T, B : ViewBinding> :
  RecyclerView.Adapter<BaseViewHolder>() {
  /**
   * 数据列表
   */
  private var data: MutableList<T> = mutableListOf()

  // 头部 布局 -- addHeadView 才会生效
  private lateinit var mHeaderLayout: LinearLayout

  // 尾部 布局 -- addFootView 才会生效
  private lateinit var mFooterLayout: LinearLayout

  /**
   * Item点击事件监听
   * 由调用方传入 lambda , itemVIew 点击执行 该 lambda
   */
  var onItemClickListener: ((view: View, position: Int) -> Unit)? = null

  /**
   * Item长按事件监听
   */
  var onItemLongClickListener: ((view: View, position: Int) -> Unit)? = null

  /**
   * 1 重写 [onCreateDefViewHolder] 由 xml--实现自定义ViewHolder
   * 2 重写 [getViewBinding]        由 xml--实现自定义ViewHolder
   */
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder =
    when (viewType) {
      HEADER_VIEW -> {
        val headerParent: ViewParent? = mHeaderLayout.parent
        if (headerParent is ViewGroup) {
          headerParent.removeView(mHeaderLayout)
        }
        BaseViewHolder(mHeaderLayout)
      }
      FOOTER_VIEW -> {
        val headerParent: ViewParent? = mFooterLayout.parent
        if (headerParent is ViewGroup) {
          headerParent.removeView(mFooterLayout)
        }
        BaseViewHolder(mFooterLayout)
      }
      else -> {
        val layoutInflater = LayoutInflater.from(parent.context)
        onCreateDefViewHolder(layoutInflater, parent, viewType).apply {
          bindViewClickListener(this) // 绑定点击事件 触发 lambda
        }
      }
    }

  /**
   * 子类 重写 [setViewBinding]
   */
  override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
    when (holder.itemViewType) {
      HEADER_VIEW, FOOTER_VIEW -> {
        return
      }
      else -> {
        // holder必须继承自 BaseBindViewHolder
        if (holder is BaseBindViewHolder<*>) {
          val realPosition = position - headerLayoutCount
          val item = getItem(realPosition)
          item?.let {
            setViewBinding(holder as BaseBindViewHolder<B>, it, realPosition)
          }
        }
      }
    }
  }

  /**
   * 子类不可重载该方法，如有需要请重写 [getDefItemViewType]
   */
  override fun getItemViewType(position: Int): Int {
    return if (hasHeaderView() && position == headerViewPosition) {
      HEADER_VIEW
    } else if (hasFooterView() && position == footerViewPosition) {
      FOOTER_VIEW
    } else {
      // 有头部 真实数据项 要 当前位置 减 1
      val realPosition = if (hasHeaderView()) position - 1 else position
      getDefItemViewType(realPosition)
    }
  }

  /**
   * 不要重写此方法，如果有需要请重写 [getDefItemCount]
   */
  override fun getItemCount(): Int = headerLayoutCount + getDefItemCount() + footerLayoutCount


  /**
   * 重写此方法，返回你的数据量
   */
  protected open fun getDefItemCount(): Int = data.size


  /**
   * 仅通过 getViewBinding 创建
   * BindingViewHolder(getViewBinding(xx,xx,xx))
   */
  private fun onCreateDefViewHolder(
    layoutInflater: LayoutInflater,
    parent: ViewGroup,
    viewType: Int,
  ): BaseViewHolder {
    return BaseBindViewHolder(getViewBinding(layoutInflater, parent, viewType))
  }

  /**
   * 子类通过 xml实现 ViewBinding，父类提供了 LayoutInflater ，viewType
   * 可以根据不同的 viewType传递不同的 viewBinding -- when
   */
  abstract fun getViewBinding(layoutInflater: LayoutInflater, parent: ViewGroup, viewType: Int): B

  /**
   * 子类重写该方法绑定数据
   * 重写 [getViewBinding] 即可实现不同ViewHolder传递
   */
  protected abstract fun setViewBinding(holder: BaseBindViewHolder<B>, item: T?, position: Int)

  /**
   * 点击绑定点击事件
   * @param holder
   */
  protected open fun bindViewClickListener(holder: BaseViewHolder) {
    holder.itemView.setOnClickListener {
      var position = holder.adapterPosition
      if (position == RecyclerView.NO_POSITION) {
        return@setOnClickListener
      }
      position -= headerLayoutCount // 当前位置 减去 头部数
      onItemClickListener?.invoke(holder.itemView, position)
    }
    holder.itemView.setOnLongClickListener {
      var position = holder.adapterPosition
      if (position == RecyclerView.NO_POSITION) {
        return@setOnLongClickListener false
      }
      position -= headerLayoutCount
      onItemLongClickListener?.invoke(holder.itemView, position)
      false
    }
  }

  /**
   * 重写此方法，通过  data[position].type 返回你的ViewType
   */
  protected open fun getDefItemViewType(position: Int): Int = super.getItemViewType(position)


  /**
   * 有 HeaderView
   * @return Boolean
   */
  private fun hasHeaderView(): Boolean =
    this::mHeaderLayout.isInitialized && mHeaderLayout.childCount > 0

  /**
   * headerView数量
   */
  private val headerLayoutCount: Int
    get() = if (hasHeaderView()) 1 else 0

  /**
   * Heater位置
   */
  private val headerViewPosition: Int = 0

  /**
   * 获取头布局
   */
  val headerBinding: LinearLayout?
    get() = if (this::mHeaderLayout.isInitialized) mHeaderLayout else null

  /**
   * headerView的子View数量
   */
  val headerViewCount: Int
    get() = if (hasHeaderView()) mHeaderLayout.childCount else 0


  /**
   * 有FooterView
   * @return Boolean
   */
  private fun hasFooterView(): Boolean =
    this::mFooterLayout.isInitialized && mFooterLayout.childCount > 0


  /**
   * footer位置
   */
  private val footerViewPosition: Int
    get() = headerLayoutCount + data.size

  /**
   * footerLayout数量
   */
  private val footerLayoutCount: Int
    get() = if (hasFooterView()) 1 else 0

  /**
   * 获取尾布局
   */
  val footerBinding: LinearLayout?
    get() = if (this::mFooterLayout.isInitialized) mFooterLayout else null

  /**
   * footerView的子View数量
   */
  val footerViewCount: Int
    get() = if (hasFooterView()) mFooterLayout.childCount else 0
  // region 头尾布局操作
  /**
   * 添加 HeaderView
   * @param view
   * @param index view在HeaderView中的位置
   * @return Int
   */
  fun addHeadView(view: View, index: Int = -1): Int {
    if (!this::mHeaderLayout.isInitialized) {
      mHeaderLayout = LinearLayout(view.context)
      mHeaderLayout.orientation = LinearLayout.VERTICAL
      mHeaderLayout.layoutParams = RecyclerView.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
      )
    }
    val childCount = mHeaderLayout.childCount
    var mIndex = index
    if (index < 0 || index > childCount) {
      mIndex = childCount
    }
    mHeaderLayout.addView(view, mIndex)
    if (mHeaderLayout.childCount == 1) {
      notifyItemInserted(headerViewPosition)
    }
    return mIndex
  }

  /**
   * 移除头布局
   * @param header
   */
  fun removeHeadView(header: View) {
    if (hasHeaderView()) {
      mHeaderLayout.removeView(header)
      if (mHeaderLayout.childCount == 0) {
        notifyItemRemoved(headerViewPosition)
      }
    }
  }

  /**
   * 移除所有头布局
   */
  fun removeAllHeadView() {
    if (hasHeaderView()) {
      mHeaderLayout.removeAllViews()
      notifyItemRemoved(headerViewPosition)
    }
  }

  /**
   * 添加FooterView
   * @param view
   * @param index view在FooterView中的位置
   * @return Int
   */
  fun addFootView(view: View, index: Int = -1): Int {
    if (!this::mFooterLayout.isInitialized) {
      mFooterLayout = LinearLayout(view.context)
      mFooterLayout.orientation = LinearLayout.VERTICAL
      mFooterLayout.layoutParams = RecyclerView.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
      )
    }
    val childCount = mFooterLayout.childCount
    var mIndex = index
    if (index < 0 || index > childCount) {
      mIndex = childCount
    }
    mFooterLayout.addView(view, mIndex)
    if (mFooterLayout.childCount == 1) {
      notifyItemInserted(footerViewPosition)
    }
    return mIndex
  }

  /**
   * 移除尾布局
   * @param header
   */
  fun removeFootView(header: View) {
    if (hasFooterView()) {
      mFooterLayout.removeView(header)
      if (mFooterLayout.childCount == 0) {
        notifyItemRemoved(footerViewPosition)
      }
    }
  }

  /**
   * 移除所有尾布局
   */
  fun removeAllFootView() {
    if (hasFooterView()) {
      mFooterLayout.removeAllViews()
      notifyItemRemoved(footerViewPosition)
    }
  }
  // endregion

  // region 数据操作
  /**
   * 获取data
   */
  fun getData(): MutableList<T> = data

  /**
   * 设置数据
   * @param list Collection<T>?
   */
  @SuppressLint("NotifyDataSetChanged")
  fun setData(list: Collection<T>?) {
    this.data.clear()
    if (list.isNullOrEmpty()) return notifyDataSetChanged()
    this.data.addAll(list)
    notifyDataSetChanged()
  }

  /**
   * 添加数据
   * @param newList 添加的数据
   */
  fun addData(newList: Collection<T>?) {
    if (newList.isNullOrEmpty()) {
      return
    }
    val nextIndex = data.size + headerLayoutCount // index 从 0 开始
    if (this.data.addAll(newList)) {
      notifyItemRangeInserted(nextIndex, newList.size)
    }
  }

  /**
   * 清空数据
   */
  @SuppressLint("NotifyDataSetChanged")
  fun clear() {
    this.data.clear()
    notifyDataSetChanged()
  }

  /**
   * 通过 索引 (该索引已经减去了 headerLayoutCount)获取指定item
   * @IntRange(from = 0,to = 20) 传参时，就限制一个范围
   * [1,2] size=2 ,position 0,1 -- >=2就会越界报错
   * @param position
   * @return T
   */
  fun getItem(@IntRange(from = 0) position: Int): T? =
    if (position >= data.size) null else data[position]

  /**
   * 获取数据的位置 如果返回 -1，表示不存在
   * @param item
   * @return Int
   */
  fun getItemPosition(item: T?): Int =
    if ((item != null && data.isNotEmpty())) data.indexOf(item) else -1

  /**
   * 更新某一个位置上的数据
   * @param position
   * @param data
   */
  fun updateItem(@IntRange(from = 0) position: Int, data: T) {
    if (position >= this.data.size) return
    this.data[position] = data
    notifyItemChanged(position + headerLayoutCount)
  }

  /**
   * 在某一个位置上添加一条数据
   * @param position
   * @param data
   */
  fun setItem(@IntRange(from = 0) position: Int, data: T) {
    // 如果超出则添加到最后
    val realPosition = if (position >= this.data.size) {
      this.data.size
    } else {
      position
    }
    this.data.add(realPosition, data)
    notifyItemInserted(realPosition + headerLayoutCount)
  }

  /**
   * 增加一条数据到末尾
   * @param data
   */
  fun addItem(data: T) {
    this.data.add(data)
    notifyItemInserted(this.data.size - 1 + headerLayoutCount)
  }

  /**
   * 移除某个位置上的数据
   * @param position
   * @return T?
   */
  fun removeAt(@IntRange(from = 0) position: Int): T? {
    if (position >= data.size) {
      return null
    }
    val remove = this.data.removeAt(position)
    notifyItemRemoved(position + headerLayoutCount)
    return remove
  }

  /**
   * 移除某个item数据
   * @param data
   * @return -1表示不存在该条数据
   */
  fun remove(data: T): Int {
    val index = this.data.indexOf(data)
    if (index != -1) {
      removeAt(index)
    }
    return index
  }

  // endregion
  companion object {
    // viewType
    const val HEADER_VIEW = 0x10000111
    const val FOOTER_VIEW = 0x10000222
  }
}